package com.hlf.common.utils;

import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.SocketException;
import java.net.URLEncoder;

public class FTPUtils {

    private FTPClient ftp;

    /**
     * 对象构造 设置将过程中使用到的命令输出到控制台
     */
    public FTPUtils() {
        ftp = new FTPClient();
        this.ftp.addProtocolCommandListener(new PrintCommandListener(
                new PrintWriter(System.out)));
    }

    /**
     * 用户FTP账号登录
     *
     * @param url      FTP地址
     * @param port     FTP端口
     * @param username 用户名
     * @param password 密 码
     * @return true/false 成功/失败
     * @throws SocketException
     * @throws IOException
     */
    private boolean login(String url, int port, String username, String password)
            throws SocketException, IOException {
        int reply;
        // 1. 连接FTP服务器
        // 如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
        ftp.connect(url, port);

        // 2. 设置编码
        // 下面三行代码必须要，而且不能改变编码格式，否则不能正确下载中文文件
        ftp.setControlEncoding("UTF-8");
        FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
        conf.setServerLanguageCode("zh");

        // 3. 登录ftp
        ftp.login(username, password);

        // 看返回的值是不是230，如果是，表示登陆成功
        reply = ftp.getReplyCode();

        // 以2开头的返回值就会为真
        if (!FTPReply.isPositiveCompletion(reply)) {
            ftp.disconnect();
            return false;
        }
        return true;
    }

    /**
     * 释放FTP
     */
    private void free() {
        if (ftp.isConnected()) {
            try {
                // 断开连接
                ftp.logout();
                ftp.disconnect();
            } catch (IOException e) {
            }
        }
    }

    /**
     * FTP文件上传
     *
     * @param url       FTP地址
     * @param port      FTP端口
     * @param username  FTP用户名
     * @param password  FTP密码
     * @param localAdr  上传文件名
     * @param remoteAdr 指定的FTP目录
     * @return
     * @throws IOException
     */
    public boolean asyncUploadFile(String url, int port, String username,
                                   String password, String localAdr, String remoteAdr)
            throws IOException {

        // 初始表示上传失败
        boolean success = false;
        /****** 验证用户登录信息 *****/
        try {
            success = login(url, port, username, password);

            if (!success) {
                return success;
            }
        } catch (IOException e) {
            return success;
        }
        // 设置PassiveMode传输
        ftp.enterLocalPassiveMode();

        // 设置FTP文件类型为二进制，如果缺省该句 传输txt正常 但图片和其他格式的文件传输出现乱码
        ftp.setFileType(FTP.BINARY_FILE_TYPE);

        /***** 对远程目录的处理 ******/
        String remoteFileName = remoteAdr;

        if (remoteAdr.contains("/")) {
            remoteFileName = remoteAdr
                    .substring(remoteAdr.lastIndexOf("/") + 1);
            String directory = remoteAdr.substring(0,
                    remoteAdr.lastIndexOf("/") + 1);

            if (!directory.equalsIgnoreCase("/")
                    && !ftp.changeWorkingDirectory(directory)) {

                // 如果远程目录不存在，则递归创建远程服务器目录
                int start = 0, end = 0;

                if (directory.startsWith("/")) {
                    start = 1;
                } else {
                    start = 0;
                }

                end = directory.indexOf("/", start);

                while (true) {

                    String subDirectory = remoteAdr.substring(start, end);

                    if (!ftp.changeWorkingDirectory(subDirectory)) {

                        if (ftp.makeDirectory(subDirectory)) {

                            ftp.changeWorkingDirectory(subDirectory);

                        } else {
                            return false;
                        }
                    }
                    start = end + 1;
                    end = directory.indexOf("/", start);
                    // 检查所有目录是否创建完毕
                    if (end <= start) {
                        break;
                    }
                }
            }
        }

        /***** 执行文件上传 ******/
        InputStream input = null;
        try {
            File f = new File(localAdr);
            // 得到目录的相应文件列表
            FTPFile[] fs = ftp.listFiles(remoteFileName);

            input = new FileInputStream(f);
            // 保存文件remoteFileName
            success = ftp.storeFile(remoteFileName, input);
            input.close();
        } catch (IOException e) {
            if (input != null) {
                input.close();
            }
        } finally {
            free();
        }
        return success;
    }

    /**
     * FTP文件上传
     *
     * @param url       FTP地址
     * @param port      FTP端口
     * @param username  FTP用户名
     * @param password  FTP密码
     * @param remoteAdr 指定的FTP目录
     * @return
     * @throws IOException
     */
    public boolean uploadFile(String url, int port, String username,
                              String password, InputStream input, String remoteAdr)
            throws IOException {

        // 初始表示上传失败
        boolean success = false;
        /****** 验证用户登录信息 *****/
        try {
            success = login(url, port, username, password);

            if (!success) {
                return success;
            }
        } catch (IOException e) {
            return success;
        }
        // 设置PassiveMode传输
        ftp.enterLocalPassiveMode();

        // 设置FTP文件类型为二进制，如果缺省该句 传输txt正常 但图片和其他格式的文件传输出现乱码
        ftp.setFileType(FTP.BINARY_FILE_TYPE);

        /***** 对远程目录的处理 ******/
        String remoteFileName = remoteAdr;

        if (remoteAdr.contains("/")) {
            remoteFileName = remoteAdr
                    .substring(remoteAdr.lastIndexOf("/") + 1);
            String directory = remoteAdr.substring(0,
                    remoteAdr.lastIndexOf("/") + 1);

            if (!directory.equalsIgnoreCase("/")
                    && !ftp.changeWorkingDirectory(directory)) {

                // 如果远程目录不存在，则递归创建远程服务器目录
                int start = 0, end = 0;

                if (directory.startsWith("/")) {
                    start = 1;
                } else {
                    start = 0;
                }

                end = directory.indexOf("/", start);

                while (true) {

                    String subDirectory = remoteAdr.substring(start, end);

                    if (!ftp.changeWorkingDirectory(subDirectory)) {

                        if (ftp.makeDirectory(subDirectory)) {

                            ftp.changeWorkingDirectory(subDirectory);

                        } else {
                            return false;
                        }
                    }
                    start = end + 1;
                    end = directory.indexOf("/", start);
                    // 检查所有目录是否创建完毕
                    if (end <= start) {
                        break;
                    }
                }
            }
        }
        try {
            success = ftp.storeFile(remoteFileName, input);
            input.close();
        } catch (IOException e) {
            if (input != null) {
                input.close();
            }
        } finally {
            free();
        }
        return success;
    }

    /**
     * 删除FTP文件
     *
     * @param url       FTP地址
     * @param port      FTP端口
     * @param username  用户名
     * @param password  密 码
     * @param remoteAdr 文件路径
     * @return true/false 成功/失败
     */
    public boolean deleteFile(String url, int port, String username,
                              String password, String remoteAdr) {

        // localAdr:要上传的文件
        // remoteAdr :上传的路径
        // 初始表示上传失败
        boolean success = false;
        try {
            success = login(url, port, username, password);
            if (!success) {
                return success;
            }
            // codeclocalAdr->localAdr
            success = ftp.deleteFile(remoteAdr);

            ftp.logout();

        } catch (IOException e) {
        } finally {
            free();
        }

        return success;
    }

    /**
     * 删除FTP文件和目录
     *
     * @param url       FTP地址
     * @param port      FTP端口
     * @param username  用户名
     * @param password  密 码
     * @param remoteAdr 文件路径
     * @return true/false 成功/失败
     */
    public boolean deleteDir(String url, int port, String username,
                             String password, String remoteAdr) {

        // localAdr:要上传的文件
        // remoteAdr :上传的路径
        // 初始表示上传失败
        boolean success = false;

        try {
            success = login(url, port, username, password);
            if (!success) {
                return success;
            }

            // String codeclocalAdr = new String(localAdr.getBytes("UTF-8"),
            // "ISO-8859-1");
            // String remoteAdr_ = new String(remoteAdr.getBytes("UTF-8"),
            // "ISO-8859-1");

            // 转到指定上传目录
            // remoteAdr_->remoteAdr
            ftp.changeWorkingDirectory(remoteAdr);

            FTPFile[] fs = ftp.listFiles(); // 得到目录的相应文件列表
            if (fs.length > 0) {

                // codeclocalAdr->localAdr
                success = ftp.removeDirectory(remoteAdr);

                ftp.logout();
            }

        } catch (IOException e) {
        } finally {
            free();
        }
        return success;
    }

    /**
     * 下载FTP文件
     *
     * @param url             FPT地址
     * @param port            FTP端口
     * @param username        用户名
     * @param password        密 码
     * @param remoteremoteAdr 远程路径
     * @param localAdr        文件名称
     * @param response        Http响应
     * @return true/false 成功/失败
     */
    public boolean downFile(String url, int port, String username,
                            String password, String remoteremoteAdr, String localAdr,
                            HttpServletResponse response) {
        boolean success = false;
        try {
            success = login(url, port, username, password);
            if (!success) {
                return success;
            }
            // 转移到FTP服务器目录
            ftp.changeWorkingDirectory(remoteremoteAdr);
            // 得到目录的相应文件列表
            FTPFile[] fs = ftp.listFiles();

            for (FTPFile ftpFile : fs) {
                if (ftpFile.getName().equals(localAdr)) {
                    // 这个就就是弹出下载对话框的关键代码
                    response.setHeader(
                            "Content-disposition",
                            "attachment;localAdr="
                                    + URLEncoder.encode(localAdr, "UTF-8"));
                    // 将文件保存到输出流outputStream中
                    File f = new File(localAdr);
                    OutputStream os = new FileOutputStream(f);
                    ftp.retrieveFile(
                            new String(ftpFile.getName().getBytes("UTF-8"),
                                    "ISO-8859-1"), os);
                    os.flush();
                    os.close();
                }
            }
            ftp.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            free();
        }
        return success;
    }

    /**
     * 读取FTP文件内容
     *
     * @param url             FPT地址
     * @param port            FTP端口
     * @param username        用户名
     * @param password        密 码
     * @param remoteremoteAdr 远程路径
     * @param localAdr        文件名称
     * @return String 文件内容
     */
    public String readFileContent(String url, int port, String username,
                                  String password, String remoteremoteAdr, String localAdr) {
        String content = null;
        try {
            boolean success = login(url, port, username, password);
            if (success) {
                // 转移到FTP服务器目录
                ftp.changeWorkingDirectory(remoteremoteAdr);

                // 得到目录的相应文件列表
                FTPFile[] fs = ftp.listFiles();

                for (FTPFile ftpFile : fs) {
                    if (ftpFile.getName().equals(localAdr)) {
                        // 这个就就是弹出下载对话框的关键代码
                        // 将文件保存到输出流outputStream中
                        File f = new File(localAdr);
                        ftp.retrieveFile(
                                new String(ftpFile.getName().getBytes("UTF-8"),
                                        "ISO-8859-1"), new FileOutputStream(f));

                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        ftp.retrieveFile(ftpFile.getName(), bos);
                        bos.flush();
                        bos.close();

                        content = new String(bos.toByteArray(), "UTF-8");
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            free();
        }
        return content;
    }

    /**
     * 判断是否重名的方法
     *
     * @param localAdr 文件名称
     * @param fs       文件列表数组
     * @return
     */
    public static boolean isDirExist(String localAdr, FTPFile[] fs) {
        for (FTPFile ftpFile : fs) {
            if (ftpFile.getName().equals(localAdr)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据重名判断的结果 生成新的文件的名称 更改的重名为 原有名字+[n], n表示数字
     *
     * @param localAdr 文件名称
     * @param fs       FTP文件列表
     * @return
     */
    public static String changeName(String localAdr, FTPFile[] fs) {
        int n = 0;
        // 创建一个可变的字符串对象 即StringBuffer对象，把localAdr值付给该对象
        StringBuffer localAdr_ = new StringBuffer("");
        localAdr_ = localAdr_.append(localAdr);

        // 重名时改名，遍历存在同名的文件
        while (isDirExist(localAdr_.toString(), fs)) {
            n++;
            String a = "[" + n + "]";
            // 最后一出现小数点的位置
            int b = localAdr_.lastIndexOf(".");
            // 最后一次"["出现的位置
            int c = localAdr_.lastIndexOf("[");
            if (c < 0) {
                c = b;
            }

            // 文件的名字
            StringBuffer name = new StringBuffer(localAdr_.substring(0, c));
            // 后缀的名称
            StringBuffer suffix = new StringBuffer(localAdr_.substring(b + 1));
            localAdr_ = name.append(a).append(".").append(suffix);
        }
        return localAdr_.toString();
    }

    public boolean rename(String remoteremoteAdr, String from, String to)
            throws IOException {
        // 转移到FTP服务器目录
        ftp.changeWorkingDirectory(remoteremoteAdr);
        return ftp.rename(from, to);
    }

    public void destroy() throws IOException {
        ftp.logout();
    }

    public static void main(String[] args) throws SocketException, IOException {
        FTPUtils ftpUtils = new FTPUtils();
        boolean success = false;
        success = ftpUtils.login("114.119.7.68", 21, "usmart_li", "usmart_li");
        if (success) {
            System.out.println(ftpUtils.rename("/webapps/imgftpservice/image/",
                    "2222222", "a"));
            System.out.println(ftpUtils.rename("/webapps/imgftpservice/image/",
                    "111111111111", "b"));
            System.out.println(ftpUtils.rename("/webapps/imgftpservice/image/",
                    "112323", "c"));
            System.out.println(ftpUtils.rename("/webapps/imgftpservice/image/",
                    "3232323", "d"));
        }
        ftpUtils.destroy();
        // try
        // {
        // for(int i= 0;i<4;i++){
        // ftp.asyncUploadFile("183.63.52.142", 21, "ftp_lhl", "123456",
        // "E:\\1236950906793.jpg",
        // "/webapps/imgftpservice/image/S2014090501000180/"+i+"222.jpg");
        // }
        // } catch (IOException e)
        // {
        // }
    }

}
